/**
 * 
 * The MIT License
 * 
 * Copyright (c) 2008 the original author or authors.
 * 
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:

 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.

 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

package com.googlecode.gchartjava;

import static com.googlecode.gchartjava.ArraysUtil.asUnmodifiableList;
import static java.util.Collections.unmodifiableList;

import java.util.LinkedList;
import java.util.List;
import java.util.Locale;

/**
 * Build a map and paramaterize it with countries and US states that you want to
 * color along a color gradient. You can also select and zoom in on a
 * {@link GeographicalArea}.
 * 
 * @author Julien Chastang (julien.c.chastang at gmail dot com)
 * 
 * @see PoliticalBoundary
 * @see USAState
 * @see Country
 * @see GeographicalArea
 * @see Color
 */
public class MapChart extends AbstractGChart {
	private static final String MAP_CHART_URL           = GCHART_URL + "?cht=t";
	private static final String GEOGRAPHICAL_AREA_PARAM = "chtm=";
	private static final String GEOCODE_PARAM           = "chld=";

	private final List<PoliticalBoundary> political = new LinkedList<PoliticalBoundary>();
	private final List<Color> colorGradientList     = new LinkedList<Color>();
	
	private final GeographicalArea geographicalArea;
	
	/**
	 * Construct a map with a {@link GeographicalArea}.
	 * 
	 * @param geographicalArea
	 *            Pass in the {@link GeographicalArea}
	 * 
	 * @see GeographicalArea
	 */
	public MapChart(final GeographicalArea geographicalArea){
		this.geographicalArea = geographicalArea;
		setSize(440, 220);
		colorGradientList.addAll(asUnmodifiableList(Color.WHITE, Color.BEIGE, Color.FORESTGREEN)); //Default
	}

	/**
	 *
	 */
	@Override
	protected void prepareData() {
		addParameter(GEOGRAPHICAL_AREA_PARAM, geographicalArea.toString().toLowerCase(Locale.US));
		setColors(unmodifiableList(colorGradientList));
		
		final StringBuilder codes = new StringBuilder();
		
		int cnt = 0;
		float[] countryColors = new float[political.size()];
		for (PoliticalBoundary pb : political) {
			codes.append(pb.getCode());
			countryColors[cnt++] = pb.getColor();
		}
		if (codes.length() > 0){
			addParameter(GEOCODE_PARAM, codes.toString());
			setData(asUnmodifiableList(new Data(countryColors)));
		}
		else {
			setData(asUnmodifiableList(new Data(-1f)));
		}
	}
		
	/**
	 * Define a default color and color gradient. {@link PoliticalBoundary}.
	 * 
	 * @param defaultColor
	 *            Default color for this map.
	 * @param colorGradient
	 *            Colors defined in the {@link PoliticalBoundary} will be
	 *            interpolated along this color gradient.
	 * 
	 * @see Color
	 */
	public void setColorGradient(final Color defaultColor, final Color...colorGradient){
		colorGradientList.clear();
		colorGradientList.add(defaultColor);
		colorGradientList.addAll(asUnmodifiableList(colorGradient));
	}
	
	/**
	 * Add a political boundary (e.g. {@link Country} or {@link USAState}).
	 * 
	 * @param politicalBoundary
	 *            Pass in a political boundary.
	 */
	public void addPoliticalBoundary(final PoliticalBoundary politicalBoundary){
		political.add(politicalBoundary);
	}
	
	/**
	 * Add one or more political boundaries (e.g. {@link Country} or {@link USAState}).
	 * 
	 * @param politicalBoundaries
	 *            Pass in one or more political boundaries.
	 */
	public void addPoliticalBoundaries(final PoliticalBoundary... politicalBoundaries){
		political.addAll(asUnmodifiableList(politicalBoundaries));
	}
	
	/**
	 * Add a list of political boundaries (e.g. {@link Country} or
	 * {@link USAState}).
	 * 
	 * @param politicalBoundaries
	 *            Pass in a list of political boundaries.
	 */
	public void addPoliticalBoundaries(final List<? extends PoliticalBoundary> politicalBoundaries){
		political.addAll(politicalBoundaries);
	}
	
	/**
	 * The default is 440x220 which is also the maximum size allowable for a
	 * MapChart.
	 * 
	 * @see com.googlecode.gchartjava.AbstractGChart#setSize(int, int)
	 */
	@Override
	public void setSize(final int x, final int y) {
		super.setSize(x, y);
	}

	/**
	 * 
	 */
	@Override
	protected String getBaseURLString() {
		return MAP_CHART_URL;
	}
}
